package com.anji.plus.gaea.security.security.url;

import com.anji.plus.gaea.cache.CacheHelper;
import com.anji.plus.gaea.constant.GaeaConstant;
import com.anji.plus.gaea.constant.GaeaKeyConstant;
import com.anji.plus.gaea.holder.UserContentHolder;
import com.anji.plus.gaea.security.GaeaSecurityProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;

import java.util.*;

/**
 * 获取当前URL所需要的角色
 * @author lr
 * @since 2021-02-25
 */
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private CacheHelper cacheHelper;

    @Autowired
    private GaeaSecurityProperties gaeaSecurityProperties;

    /**
     * 路由匹配器
     */
    private static final  AntPathMatcher antPathMatcher = new AntPathMatcher();


    /***
     * 返回该url所需要的角色列表
     *
     * @param object: 请求相关信息
     * @return:
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {

        //微服务设置为false,由网关统一鉴权,不需要
        if (gaeaSecurityProperties.getAuthDisabled()) {
            return SecurityConfig.createList(new String[0]);
        }
        FilterInvocation filterInvocation = (FilterInvocation) object;
        // 获取当前请求url
        String requestUrl = filterInvocation.getRequestUrl();
        String method = filterInvocation.getRequest().getMethod();
        String path = method + GaeaConstant.URL_SPLIT + requestUrl;

        //当前url需要的角色
        Set<String> needRoles = new HashSet<>();

        //请求方法+url路径与角色的对应关系,角色分割
        Map<String, String> urlRoleMap = cacheHelper.hashGet(GaeaKeyConstant.HASH_URL_ROLE_KEY + UserContentHolder.getOrgCode());

        //所有路径
        Map<String, String> allPathMap = cacheHelper.hashGet(GaeaKeyConstant.AUTHORITY_ALL_MAP_PREFIX);
        //当前路径包含角色
        String roleCodes = "";

        //查看allPathMap是否有path，有就精确匹配
        //查询当前请求是否在对应的权限里。即：先精确匹配(保证当前路由是需要精确匹配还是模糊匹配，防止精确匹配的被模糊匹配，
        // 比如：/user/info和/user/**同时存在，/user/info,被/user/**匹配掉)
        if (allPathMap.containsKey(path)) {
            roleCodes = urlRoleMap.get(path);
        } else {
            //模糊匹配，类似/demo/**路由匹配/demo/1
            Optional<Map.Entry<String, String>> matchUrl = urlRoleMap.entrySet().stream()
                    .filter(entry -> entry.getKey().contains(GaeaConstant.URL_REPLACEMENT) && antPathMatcher.match(entry.getKey(), path)).findFirst();

            //如果有匹配的，则将结果放入needRoles
            if (matchUrl.isPresent()) {
                roleCodes =  urlRoleMap.get(matchUrl.get().getKey());
            }
        }

        if (StringUtils.isNotBlank(roleCodes)) {
            needRoles.addAll(Arrays.asList(roleCodes.split(GaeaConstant.SPLIT)));
        }

        // 返回当前url需要的角色列表
        return SecurityConfig.createList(needRoles.toArray(new String[0]));
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }
}
